package com.maizhi.dao.impl;

import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.maizhi.dao.impl.Page;
import com.maizhi.dao.BaseDaoI;

/**
 * 数据库操作基本实现类
 * 
 */
@Repository("baseDao")
public class BaseDaoImpl<T> implements BaseDaoI<T> {

	private Map resMap = null;
	
	private List resList=null;
	
	private List<Map> mapList=null;
	
	private Object[] resObj = null;
	
	private SessionFactory sessionFactory;

	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	private Session getCurrentSession() {
		return sessionFactory.getCurrentSession();
	}

	public T save(T o) {
		this.getCurrentSession().save(o);
		return o;
	}

	public T update(T o) {
		this.getCurrentSession().update(o);
		return o;
	}

	public T saveOrUpdate(T o) {
		this.getCurrentSession().saveOrUpdate(o);
		return o;
	}

	public T merge(T o) {
		this.getCurrentSession().merge(o);
		return o;
	}

	public void delete(T o) {
		this.getCurrentSession().delete(o);
	}

	public List<T> find(String hql) {
		Query q = this.getCurrentSession().createQuery(hql);
		return q.list();
	}
	
	public List<T> find(String hql, List<Object> param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.size() > 0) {
			for (int i = 0; i < param.size(); i++) {
				q.setParameter(i, param.get(i));
			}
		}
		return q.list();
	}

	public List<T> find(String hql, Object... param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.length > 0) {
			for (int i = 0; i < param.length; i++) {
				q.setParameter(i, param[i]);
			}
		}
		return q.list();
	}

	public List<T> find(String hql, int page, int rows, List<Object> param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.size() > 0) {
			for (int i = 0; i < param.size(); i++) {
				q.setParameter(i, param.get(i));
			}
		}
		return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
	}

	public List<T> find(String hql, int page, int rows, Object... param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.length > 0) {
			for (int i = 0; i < param.length; i++) {
				q.setParameter(i, param[i]);
			}
		}
		return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
	}

	public T get(Class<T> c, Serializable id) {
		return (T) this.getCurrentSession().get(c, id);
	}
	
	

	public T get(String hql, Object... param) {
		List l = this.find(hql, param);
		if (l != null && l.size() > 0) {
			return (T) l.get(0);
		}
		return null;
	}

	public T get(String hql, List<Object> param) {
		List l = this.find(hql, param);
		if (l != null && l.size() > 0) {
			return (T) l.get(0);
		}
		return null;
	}

	public T load(Class<T> c, Serializable id) {
		return (T) this.getCurrentSession().load(c, id);
	}

	public Long count(String hql, Object... param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.length > 0) {
			for (int i = 0; i < param.length; i++) {
				q.setParameter(i, param[i]);
			}
		}
		return (Long) q.uniqueResult();
	}

	public Long count(String hql, List<Object> param) {
		Query q = this.getCurrentSession().createQuery(hql);
		if (param != null && param.size() > 0) {
			for (int i = 0; i < param.size(); i++) {
				q.setParameter(i, param.get(i));
			}
		}
		return (Long) q.uniqueResult();
	}

	public Integer executeHql(String hql) {
		Query q = this.getCurrentSession().createQuery(hql);
		return q.executeUpdate();
	}

	public List findBySql(String sql) {
		SQLQuery q= this.getCurrentSession().createSQLQuery(sql);
		return q.list();
	}

	public List findBySql(String sql, int page, int rows) {
		SQLQuery q= this.getCurrentSession().createSQLQuery(sql);
		return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
	}

	public List findBySql(T t, String sql) {
		SQLQuery q= this.getCurrentSession().createSQLQuery(sql).addEntity(t.getClass());
		return q.list();
	}

	public List findBySql(T t, String sql, int page, int rows) {
		SQLQuery q= this.getCurrentSession().createSQLQuery(sql).addEntity(t.getClass());
		return q.setFirstResult((page - 1) * rows).setMaxResults(rows).list();
	}
	
	public List findBySqlAndPage(String sql, Object[] values, int min, int max) {
		SQLQuery sq = this.getCurrentSession().createSQLQuery(sql);
		if(min>=0 && max>=0){
			sq.setFirstResult(min);
			sq.setMaxResults(max);
		}
		
		if(values!=null && values.length>0){
			for(int i=0;i<values.length;i++){
				sq.setParameter(i, values[i]);
			}
		}
		
		return sq.list();
		
	}
	
	public List<T> findByHqlAndPage(String hql, Object[] values, int min, int max) {
        Query q = this.getCurrentSession().createQuery(hql);
        if(min>=0 && max>=0){
        	q.setFirstResult(min);
        	q.setMaxResults(max);
        }
        
        if(values!=null && values.length>0){
        	for(int i=0;i<values.length;i++){
        		q.setParameter(i, values[i]);
        	}
        }
        return q.list();
    
	}

	public List<T> findByHqlAndPage(String hql,Page page){
		return findByHqlAndPage(hql,null,page.getFirstReslut(),page.getPerPageRow());
	}
	
	public List<T> findByHqlAndPage(String hql,Object[] values,Page page){
		return findByHqlAndPage(hql,values,page.getFirstReslut(),page.getPerPageRow());
	}
	
	public List<Map>    findBySqlAndPageMap(String sql,Page page){
		return findBySqlAndPageMap(sql,null,page.getFirstReslut(),page.getPerPageRow());
	}
	
	public List<Map>    findBySqlAndPageMap(String sql,Object[] values,Page page){
		return findBySqlAndPageMap(sql,values,page.getFirstReslut(),page.getPerPageRow());
	}
	
	public List<Map>    findBySqlAndPageMap(String sql,Object[] values,int min,int max){
		SQLQuery sq = this.getCurrentSession().createSQLQuery(sql);
		String[] ls = getSqlCols(sql);
		if(min>=0 && max>=0){
			sq.setFirstResult(min);
			sq.setMaxResults(max);
		}
		
		if(values!=null && values.length>0){
			for(int i=0;i<values.length;i++){
				sq.setParameter(i, values[i]);
			}
		}
		
		resList = sq.list();
		if(resList!=null && resList.size()>0){
			mapList = new ArrayList();
			for(int i=0;i<resList.size();i++){
				resObj = (Object[])resList.get(i);
				if(resObj!=null && resObj.length>0){
					resMap = new HashMap();
					for(int j=0;j<resObj.length;j++){
						resMap.put(ls[j], resObj[j]);
					}
				}
				mapList.add(resMap);
			}
		}
		return mapList;
	}
	
	public String[] getSqlCols(String sql){
		String[] cols = null;
		try {
			PreparedStatement pstat = org.springframework.orm.hibernate4.SessionFactoryUtils.getDataSource(getSessionFactory()).getConnection().prepareStatement("select * from ("+sql+") t where 1=2");
			ResultSet rs = (ResultSet) pstat.executeQuery();
			ResultSetMetaData rsd = rs.getMetaData();
			int cls = rsd.getColumnCount();
			if(cls>0){
				cols = new String[cls];
				for(int i=1;i<=cls;i++){
					cols[i-1]=rsd.getColumnName(i);
				}
			}
			if (rs != null) {
	            try {
	                rs.close();
	            } catch (SQLException e) {
	                e.printStackTrace();
	            }
	        }

	        // 关闭声明
	        if (pstat!= null) {
	            try {
	            	pstat.close();
	            } catch (SQLException e) {
	                e.printStackTrace();
	            }
	        }
	        
		} catch (HibernateException e) {
			e.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return cols;
	}
	
	public int    getSqlCounts(String sql){
		SQLQuery q = this.getCurrentSession().createSQLQuery(sql);
		return q.list().size();
	}
	
	public int    getHqlCounts(String hql){
		Query q = this.getCurrentSession().createQuery(hql);
		return q.list().size();
	}
	
}
